<?php

namespace app\api\service;

use app\model\Money;
use app\model\User;
use app\common\Common;
use app\common\Error;
use think\facade\Cache;
use app\model\UserLoginRecord;
use app\model\Link;
use app\model\Applet;
use app\model\PayRecord;
use think\facade\Db;
use think\facade\Queue;

class KwaiService
{
    private $model;
    private $userLoginRecordModel;
    private $linkModel;
    private $appletModel;
    private $payRecordModel;

    public function __construct(User $model, UserLoginRecord $userLoginRecordModel, Link $linkModel, Applet $appletModel, PayRecord $payRecordModel)
    {
        $this->model = $model;
        $this->userLoginRecordModel = $userLoginRecordModel;
        $this->linkModel = $linkModel;
        $this->appletModel = $appletModel;
        $this->payRecordModel = $payRecordModel;
    }

    // 快手登录
    public function kwaiUserLogin($params)
    {
        $appId = $params['app_id'];
        $appletData = $this->appletModel->getInfoByWhere(['app_id' => $appId], 'id, app_id, app_secret');

        if (empty($appletData)) {
            return ['message' => Error::APPID_PARAMATER_ERROR];
        }
        $secret = $appletData['app_secret'];

        $code = $params['code'];

        $url = 'https://open.kuaishou.com/oauth2/mp/code2session';

        $requestData = [
            'app_id' => $appId,
            'app_secret' => $secret,
            'js_code' => $code
        ];

        $postData = http_build_query($requestData);

        $result = Common::curlGetRequest($url, $postData, ['Content-Type: application/x-www-form-urlencoded']);

        $result = json_decode($result, true);

        if ($result['result'] != 1) {
            return ['message' => Error::FAIL_AUTHORIZED_lOGIN];
        }

        $openId = $result['open_id'];
        $userInfo = $this->model->getInfoByOpenId($openId, 'id, user_name, avatar');

        $officialAccountId = '';
        $saveData = [
            'platform' => 3,
            'open_id' => $openId,
            'last_login_time' => time(),
            'updated_at' => time()
        ];
        //获取未从链接id进来的用户对应的公众号id
        $officialAccountData = Db::name('official_accounts')->where(['applet_id' => $appletData['id']])->field('id')->limit(1)->select()->toArray();
        if(!empty($officialAccountData)){
            $saveData['official_account_id'] = $officialAccountData[0]['id'];//公众号id
        }

        $ip = empty($params['ip']) ? '' : $params['ip'];
        $ua = empty($params['ua']) ? '' : $params['ua'];

        $redis = Cache::store('redis')->handler();

        if (!empty($params['is_capitalization']) && $params['type'] == 2) {
            // 快手小程序直跳
            // file_put_contents('./test.txt', date('Y-m-d H:i:s').' ：'.json_encode($params).';'.PHP_EOL, FILE_APPEND);
            $saveData['link_id'] = $params['link_id'];
            $saveData['activation_time'] = date('Y-m-d H:i:s');
            if (!empty($params['callback'])) {
                $saveData['clickid'] = $params['callback'];

                $eventTime = Common::msectime();
                $url = 'http://ad.partner.gifshow.com/track/activate?callback=' . $params['callback'] . '&event_type=1&event_time=' . $eventTime;
                $result = Common::curlRequest($url, 'GET');

                $redis->select(6);
                $monitoringData = $redis->get(md5($params['callback']));

                if ($monitoringData) {
                    $monitoringData = json_decode($monitoringData, true);
                    $saveData['advertiser_id'] = $monitoringData['advertiser_id'];
                } else {
                    $saveData['advertiser_id'] = $params['link_id'];
                }
            }

            if (!empty($params['link_id'])) {
                $linkData = $this->linkModel->getInfoByWhere(['id' => $params['link_id']], 'official_account_id');
                $officialAccountId = $linkData['official_account_id'];
                $saveData['official_account_id'] = $officialAccountId;
            }

        } else if (!empty($params['link_id'])) {
            $saveData['link_id'] = $params['link_id'];
            $saveData['activation_time'] = date('Y-m-d H:i:s');

            if ($ip && $ua) {
                $saveData['ip'] = $ip;
                $saveData['ua'] = $ua;
                $redis->select(6);
                $monitoringData = $redis->get(md5($ip . $ua . $params['link_id']));

                if ($monitoringData) {

                    $monitoringData = json_decode($monitoringData, true);
                    if (!empty($monitoringData['advertiser_id'])) {
                        $saveData['advertiser_id'] = $monitoringData['advertiser_id'];
                        // $advertiserId = $monitoringData['advertiser_id'];
                    }

                    if (!empty($monitoringData['clickid'])) {
                        $saveData['clickid'] = $monitoringData['clickid'];
                        $clickid = $monitoringData['clickid'];

                        if (!empty($params['type']) && $params['type'] == 2) {
                            // 快手激活回传
                            $eventTime = Common::msectime();
                            $url = 'http://ad.partner.gifshow.com/track/activate?callback=' . $clickid . '&event_type=1&event_time=' . $eventTime;
                            $result = Common::curlRequest($url, 'GET');
                        }
                    }
                }
            }

            $linkData = $this->linkModel->getInfoByWhere(['id' => $params['link_id']], 'official_account_id');
            $officialAccountId = $linkData['official_account_id'];

            $saveData['official_account_id'] = $officialAccountId;
        }

        if ($userInfo) {
            $saveData['id'] = $userInfo['id'];
            $saveData['applet_id'] = $appletData['id'];
        } else {
            $saveData['applet_id'] = $appletData['id'];
            $saveData['register_date'] = intval(date('Ymd'));
            $saveData['created_at'] = time();
        }

        $uid = $this->model->edit($saveData);
        if ($uid == 3279450 || $uid == 1265895) {
            file_put_contents('./public_login.txt', date('Y-m-d H:i:s').' ：'.json_encode($params).'；'.PHP_EOL, FILE_APPEND);
        }
        $token = Common::createToken($uid);

        $redis->select(8);
        $key = config('redis_key.api.user_login');
        $linkIdKey = config('redis_key.api.user_login_link_id');
        $expire = config('redis_key.api.user_login_expire');
        $expireTime = time() + $expire;

        $boolUserId = $redis->set($token, $uid, $expire);
        $mountKey = config('redis_key.api.user_login_mount_key').$uid;
        if (!empty($params['link_id'])) {
            $redis->del($mountKey);
            $redis->set($linkIdKey . $token, $params['link_id'], $expire);
        }
        $boolUser = $redis->set($key . $uid, json_encode($params), $expire);

        if (empty($boolUserId) || empty($boolUser)) {
            return [];
        }

        // 是否是通过挂载的小程序进来
        if (!empty($params['scene'])) {
            // file_put_contents('./public_login.txt', date('Y-m-d H:i:s').' ：'.json_encode($params).'；'.PHP_EOL, FILE_APPEND);
            if (in_array($params['scene'], ['011009', '011044', '011001'])) {
                $redis->set($mountKey, 2, $expire+(15*60*60*24));
            }
            // $mountVideoIdKey = config('redis_key.api.user_login_mount_video_id_key').$uid;
            // $mountVideoIdKeyExpire = config('redis_key.api.user_login_mount_video_id_key_expire');
            // $redis->set($mountVideoIdKey, $params['vid'], $mountVideoIdKeyExpire);
        }

        $loginRecordData = [
            'uid' => $uid,
            'date' => date('Ymd'),
            'month' => date('Ym'),
            'ip' => Common::getClientIp(),
            'created_at' => time(),
        ];
        if ($officialAccountId) {
            $loginRecordData['official_account_id'] = $officialAccountId;
        }
        $this->userLoginRecordModel->edit($loginRecordData);

        $data = ['token' => $token, 'id' => $uid, 'status' => 0, 'expire_time' => $expireTime, 'official_account_id' => $officialAccountId, 'user_name' => '', 'avatar' => '', 'link_id' => ''];
        $data['link_id'] = !empty($params['link_id']) ? $params['link_id'] : '';

        if ($userInfo) {
            $data['user_name'] = $userInfo['user_name'];
            $data['avatar'] = $userInfo['avatar'];
        }
        if (!empty($params['link_id'])) {
            $return['link_id'] = $params['link_id'];
        }
        return $data;
    }

    // 预支付下单
    public function advancePaymentOrder($params, $uid)
    {
        $name = isset($params['name']) ? $params['name'] : '测试数据';
        $name = addslashes(strip_tags($name));
        $total = isset($params['total_fee']) ? $params['total_fee'] : '1';
        $number = $params['number'];
        $type = isset($params['type']) ? $params['type'] : 1;

        $userInfo = $this->model->getInfoById($uid, 'link_id, activation_time, official_account_id, interpolate_id, advertiser_id, applet_id, open_id, mobile_system');
        $orderNo = Common::Snowflake();//date('YmdHis') . rand(1000, 10000);
        //判断用户如果是挂载进入就将用户link_id清空
        // $mountKey =config('redis_key.api.user_login_mount_key').$uid;
        // $redis = Cache::store('redis')->handler();
        // $mount=$redis->get($mountKey);
        // if(!empty($mount)&&$mount==1){
        //     $userInfo['link_id']='';
        // }
        $payRecordData = [
            'source' => 3,
            'uid' => $uid,
            'order_no' => $orderNo,
            'name' => $name,
            'type' => $type,
            'number' => $number,
            'total_fee' => round($total / 100, 2),
            'created_at' => time(),
            'consume_date'    => date('Ymd'),
            'consume_month'   => date('Ym'),
            'link_id'         => !empty($userInfo['link_id']) ? $userInfo['link_id'] : null,
            'activation_time' => !empty($userInfo['activation_time']) ? $userInfo['activation_time'] : null,
            'activation_date' => !empty($userInfo['activation_time']) ? date('Ymd', strtotime($userInfo['activation_time'])) : null,
            'official_account_id' => !empty($userInfo['official_account_id']) ? $userInfo['official_account_id'] : null,
            'interpolate_id' => !empty($userInfo['interpolate_id']) ? $userInfo['interpolate_id'] : null,
            'advertiser_id' => !empty($userInfo['advertiser_id']) ? $userInfo['advertiser_id'] : null,
            'device_type' => WechatService::getDeviceType($userInfo['mobile_system'] ?? ''),
            'activity_id' => $params['activity_id'] ?? 0,
        ];

        if (!empty($params['video_id'])) {
            $payRecordData['video_id'] = $params['video_id'];
        }
        $payId = $this->payRecordModel->edit($payRecordData);

        // 生成预支付请求数据
        $appletData = $this->appletModel->getInfoById($userInfo['applet_id'], 'app_id, app_secret');
        $accessToken = Common::getKwaiAppletAccessToken($appletData['app_id'], $appletData['app_secret']);

        $url = 'https://open.kuaishou.com/openapi/mp/developer/epay/create_order?app_id=' . $appletData['app_id'] . '&access_token=' . $accessToken;

        $requestData = [
            'out_order_no' => $orderNo,
            'open_id' => $userInfo['open_id'],
            'total_amount' => intval($total),
            'subject' => $name,
            'detail' => $type == 1 ? '普通充值' : '会员充值',
            'type' => 1273,
            'expire_time' => 86400,
            'notify_url' => 'https://' . config('app.app_host') . '/api/kwai/callback'
        ];

        $sign = self::sign($requestData, $appletData);
        $requestData['sign'] = $sign;

        $prepayData = Common::curlRequest($url, 'POST', json_encode($requestData), ['Content-Type: application/json']);

        $result = json_decode($prepayData, true);

        if ($result['result'] != 1) {
            return ['message' => $result['error_msg']];
        }
        $result['order_info']['order_no_new']=$orderNo;
        return $result['order_info'];
    }

    // 签名
    public function sign($body, $appletData)
    {
        $body['app_id'] = $appletData['app_id'];
        ksort($body);
        $string = '';
        foreach ($body as $key => $value) {
            $string .= $key . '=' . $value . '&';
        }
        $string = substr($string, 0, strlen($string) - 1) . $appletData['app_secret'];
        return md5($string);
    }

    // 支付回调
    public function payCallBack($params)
    {
        // 记录日志
        $log = fopen('./kwai_pay_callback.txt', 'a+');
        fwrite($log, json_encode($params) . PHP_EOL);
        fclose($log);

        if (!empty($params['data']['status']) && $params['data']['status'] != 'SUCCESS') {
            return ['result' => 0, 'message_id' => $params['message_id']];
        }

        $orderNo = $params['data']['out_order_no'];

        Db::startTrans();
        try {
            // 加锁
            $info = Db::name('pay_record')->field('id, number, type, uid, link_id, total_fee, status, created_at, advertiser_id')->where(['order_no' => $orderNo])->lock(true)->find();

            if (empty($info) || !empty($info['status'])) {
                Db::rollback();
                return ['result' => 0, 'message_id' => $params['message_id']];
            }

            // 修改支付状态
            $paySaveData = [
                'status' => 1,
                'pay_time' => time(),
                'platform_order_no' => $params['data']['ks_order_no']
            ];
            if ($params['data']['channel'] == 'WECHAT') {
                $paySaveData['pay_type'] = 1;
                $paySaveData['wechat_order_no'] = $params['data']['trade_no'];
            } else {
                $paySaveData['pay_type'] = 2;
                $paySaveData['wechat_order_no'] = $params['data']['trade_no'];
            }
            // 修改支付状态
            $bool = PayRecord::update($paySaveData,['id' => $info['id']]);

            if (!$bool) {
                Db::rollback();
                return ['result' => 0, 'message_id' => $params['message_id']];
            }

            $userInfo = Db::name('user')->where(['id' => $info['uid']])->field('money, expiration_time, first_charge_date, clickid, interpolate_id, activation_time, ip, ua, applet_id, open_id')->lock(true)->find();

            if (in_array($info['type'],[Money::TYPE_COMMON,Money::TYPE_ACTIVITY])) {
                // 普通充值
                $saveData = [
                    'money' => $userInfo['money'] + $info['number']
                ];
            }  elseif ($info['type'] == Money::TYPE_UNLOCK_ALL) {
                $saveData = [
                    //'is_members'      => 0,
                    'updated_at' =>  time(),
                ];
            } else {
                // 会员
                $expirationTime = self::getMemberExpireTime($info['type'], $userInfo['expiration_time']);

                $saveData = [
                    'is_members'      => 1,
                    'expiration_time' => $expirationTime
                ];
            }

            // 是否支付过
            $isCharge = Db::name('pay_record')->field('id')->where(['uid' => $info['uid'], 'status' => 1])->find();
            if (!$isCharge) {
                $saveData['first_charge_date'] = time();
            }

            // 现有的余额加充值的K币或修改成会员
            $saveMoneyBool = Db::name('user')->where(['id' => $info['uid']])->update($saveData);

            if (!$saveMoneyBool) {
                Db::rollback();
                return ['result' => 0, 'message_id' => $params['message_id']];
            }

            if (!empty($userInfo['interpolate_id'])) {
                Db::name('keyword_reply')->where(['id' => $userInfo['interpolate_id']])->inc('order_amount', $info['total_fee'])->update();
            }

            if (!empty($info['link_id'])) {
                $linkData = Db::name('link')->where(['id' => $info['link_id']])->field('recharge_price')->find();
                $rechargePrice = $linkData['recharge_price'] + round($info['total_fee'], 2);
                Db::name('link')->where(['id' => $info['link_id']])->update([
                    'recharge_price' => $rechargePrice
                ]);
            }

            Db::commit();
        } catch (\Exception $e) {
            Db::rollback();
            flog(['error' => $e->getMessage().'_'.$e->getLine(), 'out_trade_no' => $orderNo], 'kwai_pay_callback');
            return 0;
        }

        // 根据回传比例回传对应平台
        if ($info['link_id'] && $userInfo['clickid'] && $info['advertiser_id']) {

            $info['clickid'] = $userInfo['clickid'];
            $info['open_id'] = $userInfo['open_id'];
            $info['applet_id'] = $userInfo['applet_id'];
            $info['activation_time'] = $userInfo['activation_time'];

            // 回传队列延时3秒后执行
            $jobQueueName = 'postBack';
            Queue::push('app\job\PostBack', $info, $jobQueueName);
        }

        // 快手订单同步
        $appletData = Db::name('applet')->where(['app_id' => $params['app_id']])->field('app_id, app_secret')->find();
        $accessToken = Common::getKwaiAppletAccessToken($appletData['app_id'], $appletData['app_secret']);

        $url = 'https://open.kuaishou.com/openapi/mp/developer/order/v1/report?app_id='.$appletData['app_id'].'&access_token='.$accessToken;

        $uploadUrl = 'https://open.kuaishou.com/openapi/mp/developer/file//img/uploadWithUrl?app_id='.$appletData['app_id'].'&access_token='.$accessToken.'&url=https://shortplay.sybyn.top/static/23cffcc69be52d5a52a9601165fb495.png';

        $uploadResult = Common::curlRequest($uploadUrl, 'POST');

        $result = json_decode($uploadResult, true);
        if ($result['result'] == 1) {
            $productCoverImgId = $result['data']['imgId'];
        }

        if (!empty($productCoverImgId)) {
            // 订单同步
            $requestData = [
                'out_biz_order_no' => $orderNo,
                'out_order_no' => $orderNo,
                'open_id' => $userInfo['open_id'],
                'order_create_time' => $info['created_at'],
                'order_status' => 11,
                'order_path' => '/pages/recharge/recharge',
                'product_cover_img_id' => $productCoverImgId
            ];

            $result = Common::curlRequest($url, 'POST', json_encode($requestData), ['Content-Type: application/json']);

            $result = json_decode($result, true);

            if ($result['result'] != 1) {
                // 同步异常
                $saveData = [
                    'order_no' => $orderNo,
                    'uid' => $info['uid'],
                    'pay_id' => $info['id'],
                    'sync_status' => 2,
                    'sync_error_msg' => $result['error_msg'],
                    'created_at' => time(),
                    'app_id' => !empty($params['app_id']) ? $params['app_id'] : ''
                ];
                Db::name('kwai_order_sync_settlement')->insert($saveData);
            } else {
                $saveData = [
                    'order_no' => $orderNo,
                    'uid' => $info['uid'],
                    'pay_id' => $info['id'],
                    'sync_status' => 1,
                    'created_at' => time(),
                    'app_id' => !empty($params['app_id']) ? $params['app_id'] : ''
                ];
                Db::name('kwai_order_sync_settlement')->insert($saveData);
            }
        }

        return ['result' => 1, 'message_id' => $params['message_id']];
    }

    // 获取会员到期时间
    public function getMemberExpireTime($type, $timestamp = 0)
    {
        if ($timestamp && $timestamp > time()) {
            // 大于当前时间表示续费
            switch ($type) {
                case 2: // 年卡会员
                    $expirationTime = strtotime('+1day', strtotime('+12' . ' month', $timestamp));
                    break;
                case 3: // 半年会员
                    $expirationTime = $timestamp + 86400 * 180;
                    break;
                case 4: // 季卡会员
                    $expirationTime = $timestamp + 86400 * 90;
                    break;
                case 5: // 60天会员
                    $expirationTime = $timestamp + 86400 * 60;
                    break;
                case 6: // 30天会员
                    $expirationTime = $timestamp + 86400 * 30;
                    break;
                case 7: // 10天会员
                    $expirationTime = $timestamp + 86400 * 10;
                    break;
                case 8: // 7天会员
                    $expirationTime = $timestamp + 86400 * 7;
                    break;
                case 11: // 3天会员
                    $expirationTime = $timestamp + 86400 * 3;
                    break;
                case 15: // 1天会员
                    $expirationTime = $timestamp + 86400 * 1;
                    break;
                default:
                    $expirationTime = time();
                    break;
            }
        } else {
            // 开通会员或会员已过期
            switch ($type) {
                case 2: // 年卡会员
                    $expirationTime = strtotime(date('Y-m-d', strtotime('+1day', strtotime(date('Y-m-d', strtotime('+12' . ' month'))))));
                    break;
                case 3: // 半年会员
                    $expirationTime = strtotime(date('Y-m-d')) + 86400 * 181;
                    break;
                case 4: // 季卡会员
                    $expirationTime = strtotime(date('Y-m-d')) + 86400 * 91;
                    break;
                case 5: // 60天会员
                    $expirationTime = strtotime(date('Y-m-d')) + 86400 * 61;
                    break;
                case 6: // 30天会员
                    $expirationTime = strtotime(date('Y-m-d')) + 86400 * 31;
                    break;
                case 7: // 10天会员
                    $expirationTime = strtotime(date('Y-m-d')) + 86400 * 11;
                    break;
                case 8: // 7天会员
                    $expirationTime = strtotime(date('Y-m-d')) + 86400 * 8;
                    break;
                case 11: // 3天会员
                    $expirationTime = strtotime(date('Y-m-d')) + 86400 * 4;
                    break;
                case 15: // 1天会员
                    $expirationTime = strtotime(date('Y-m-d')) + 86400 * 2;
                    break;
                default:
                    $expirationTime = time();
                    break;
            }
        }
        return $expirationTime;
    }
}
